package com.mzpai.util;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.UUID;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.lang.RandomStringUtils;
import org.springframework.util.DigestUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.gexin.fastjson.JSONObject;



public class StringUtils extends org.springframework.util.StringUtils{
	
	private static final String CODE_STR = "ABCDEFGHIGKLMNOPQRSTUVWXYZ1234567890";
	private static final String CODE_DIGT = "1234567890";
	private static final String __randChars = "0123456789abcdefghigklmnopqrstuvtxyzABCDEFGHIGKLMNOPQRSTUVWXYZ";

	private final static Random __random = new Random(System.currentTimeMillis());
	
	/**
     * 判断是否为空字符串最优代码
     * @param str
     * @return 如果为空，则返回true
     */
    public static boolean isEmpty(String str){
        return str == null || str.trim().length() == 0;
    }

    /**
     * 判断字符串是否非空
     * @param str 如果不为空，则返回true
     * @return
     */
    public static boolean isNotEmpty(String str){
        return !isEmpty(str);
    }


    public static String generteBatchNum(String source, int length) {
        String value = String.valueOf(source);
        while (value.length() < length) {
            value = "0" + value;
        }
        return value;
    }

    /**
     * @return : String
     * @Description : 字符串快速连接方法
     * @Creation Date : 2016年5月6日 上午11:30:04
     * @Author : wangchao
     */
    public static String append(String... values) {
        if (values == null || values.length == 0)
            return "";
        StringBuilder builder = new StringBuilder();
        for (String val : values) {
            builder.append(val);
        }
        return builder.toString();
    }

    /**
     * 打印堆栈数量，超过这个数量会省略输出
     */
    public static final int PRINT_STACK_COUNT = 5;

    private static final String FORMAT_STRING = "yyyy-MM-dd HH:mm:ss";
    private static final ThreadLocal<SimpleDateFormat> format = new ThreadLocal<SimpleDateFormat>() {
        @Override
        protected synchronized SimpleDateFormat initialValue() {
            return new SimpleDateFormat(FORMAT_STRING);
        }

        ;
    };

    /**
     * 判断输入字符串是否满足以下非空条件：<br>
     * 不为空，剪头去尾后长度大于0，不论大小写字符串都不等于null
     *
     * @param str 输入要判断的串
     * @return 根据依据判断出的布尔结果
     */
    public static final boolean isNullOrBlank(String str) {
        if (str == null) {
            return true;
        }
        if (str.length() <= 0) {
            return true;
        }
        return false;
    }

    /**
     * 转换为公里
     *
     * @param dise
     * @return
     */
    public static final String distanceToString(Double dise) {
        String distance = "";
        if (dise >= 1000) {
            distance = String.valueOf(dise / 1000).substring(0, String.valueOf(dise / 1000).indexOf(".") + 3) + "公里";

        } else if (dise > 0 && dise < 1000) {
            distance = String.valueOf(dise / 1000).substring(0, String.valueOf(dise / 1000).indexOf(".") + 3) + "公里";
        } else {
            distance = String.valueOf(dise) + "公里";
        }
        return distance;
    }


    /**
     * 非null而且内容不为空
     *
     * @param str
     * @return
     */
    public static final boolean notNullOrBlank(String str) {
        if (str == null) {
            return false;
        }
        if (str.length() <= 0) {
            return false;
        }
        return true;
    }

    /**
     * 安全的trim方式，剪头去尾，在输入为空的情况下也能安全剪除字符串两端的空白
     *
     * @param str
     * @return 返回绝不为空，至少为长度为0的串
     */
    public static final String trim(String str) {
        if (str == null) {
            return "";
        }
        return str.trim();
    }

    /**
     * 获得字符串的数组表示
     *
     * @param srcStr   使用(delim)符号分割的字符串
     * @param delim    分割符，如果符号不是打印符号，则使用空格替代
     * @param zeroSize 决定当拆不出任何数组的时候，是返回null还是零长度的对象，如果为true则返回0长度对象，否则直接null
     * @return
     */
    public static final String[] splitToArray(String srcStr, String delim,
                                              boolean zeroSize) {
        String[] strArray = null;
        if (!isNullOrBlank(srcStr)) {
            // 如果分割符不是特殊符号，则默认使用空格分割
            if (isNullOrBlank(delim)) {
                delim = " ";
            }
            StringTokenizer stringTokenizer = new StringTokenizer(srcStr, delim);
            strArray = new String[stringTokenizer.countTokens()];
            for (int i = 0; stringTokenizer.hasMoreTokens(); i++) {
                strArray[i] = stringTokenizer.nextToken();
            }
        }
        if (zeroSize && strArray == null) {
            // 为了节省空间，需要指定长度为0
            strArray = new String[0];
        }
        return strArray;
    }

    /**
     * null convert to blank
     *
     * @param string
     * @return
     */
    public static final String null2blank(String string) {
        return string == null ? "" : string;
    }

    /**
     * 移除字符串的空格
     *
     * @param src
     * @return
     */
    public static final String removeSpace(String src) {
        if (src == null) {
            return "";
        }
        char[] ss = src.toCharArray();
        int j = 0;
        for (int i = 0; i < ss.length; i++) {
            if (ss[i] != ' ') {
                ss[j++] = ss[i];
            }
        }
        return new String(ss).substring(0, j);
    }

    /**
     * 将异常转换为堆栈输出串
     *
     * @param e 需要输出的异常对象
     * @return 转换出的字符串，不为空
     */
    public static final String toStacksString(Throwable e) {
        if (e == null) {
            return "";
        }
        StringBuffer eStrBuf = new StringBuffer("以下是异常（");
        eStrBuf.append(e.getClass().getName());
        eStrBuf.append(':');
        eStrBuf.append(e.getMessage());
        eStrBuf.append("）的堆栈信息：\r\n");
        StackTraceElement[] traces = e.getStackTrace();
        int tracesSize = traces.length;
        for (int i = 0; i < tracesSize; i++) {
            eStrBuf.append("\tat ");// 在堆栈行开始增加空格
            StackTraceElement trace = traces[i];
            eStrBuf.append(trace.toString());
            eStrBuf.append("\r\n");
        }
        ex(eStrBuf, e.getCause());
        return eStrBuf.toString();
    }

    /**
     * 将异常输出到字符缓冲中
     *
     * @param sb 需要输出到的目标字符串缓冲，不可为空
     * @param t  需要输出的异常
     * @return 如果还有引起异常的源，那么返回true
     */
    private final static boolean ex(StringBuffer sb, Throwable t) {
        if (t != null) {
            sb.append("Caused by: ");
            sb.append(t.getClass().getName());
            sb.append(": ");
            sb.append(t.getMessage());
            sb.append("\r\n");
            StackTraceElement[] traces = t.getStackTrace();
            int tracesSize = traces.length;
            for (int i = 0; i < tracesSize; i++) {
                if (i < PRINT_STACK_COUNT) {
                    sb.append("\tat ");// 在堆栈行开始增加空格
                    StackTraceElement trace = traces[i];
                    sb.append(trace.toString() + "\r\n");
                } else {
                    sb.append("\t... ");
                    sb.append(tracesSize - PRINT_STACK_COUNT);
                    sb.append(" more\r\n");
                    break;
                }
            }
            if (ex(sb, t.getCause())) {
                return true;
            }
        }
        return false;
    }

    /**
     *
     * @param str
     * @param codec
     * @return
     */
    public static final String encode(String str, String codec) {
        try {
            return new String(str.getBytes("UTF-8"), codec);
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }
    
    /**
	 * unicode 转字符串
	 */
	public static String unicodeToString(final String dataStr) {
	    int start = 0;
	    int end = 0;
	    final StringBuffer buffer = new StringBuffer();
	    while (start > -1) {
	        end = dataStr.indexOf("\\u", start + 2);
	        String charStr = "";
	        if (end == -1) {
	            charStr = dataStr.substring(start + 2, dataStr.length());
	        } else {
	            charStr = dataStr.substring(start + 2, end);
	        }
	        char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串。
	        buffer.append(new Character(letter).toString());
	        start = end;
	    }
	    return buffer.toString();
	}

    /**
     *
     * @param str
     * @param codec
     * @return
     */
    public static final String decode(String str, String codec) {
        try {
            return new String(str.getBytes(codec), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    /**
     * 两个字符串比较(去除空格)
     *
     * @param str1
     * @param str2
     * @return
     */
    public static final boolean compare(String str1, String str2) {

        if (trim(str1).equals(trim(str2))) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 两个字符串比较
     *
     * @param str1
     * @param str2
     * @return
     */
    public static final boolean compareComplete(String str1, String str2) {
        if (trimComplete(str1).equals(trimComplete(str2))) {
            return true;
        } else {
            return false;
        }
    }

    public static final String trimComplete(String str) {
        if (str == null) {
            return "";
        }
        return str;
    }


    public static final boolean isIn(String substring, String[] source) {

        if (source == null || source.length == 0) {
            return false;
        }
        for (int i = 0; i < source.length; i++) {
            String aSource = source[i];
            if (aSource.equals(substring)) {
                return true;
            }
        }
        return false;
    }


    /**
     * convertParams(转换为Map参数)
     *
     * @param source PO对象
     * @param params 参数Map void
     * @throws
     * @since 1.0.0
     */
    public static void convertParams(Object source, Map<String, Object> params) {
        if (source == null || params == null) {
            return;
        }
        convertParams(source, params, source.getClass(), false);
    }

    public static void convertNotEmptyParams(Object source, Map<String, Object> params) {
        if (source == null || params == null) {
            return;
        }
        convertParams(source, params, source.getClass(), true);
    }

    private static void convertParams(Object source, Map<String, Object> params, Class<?> c, boolean notEmpty) {
        Class<?> s = c.getSuperclass();
        if (s != null) {
            if (s.equals(Object.class) == false) {
                convertParams(source, params, s, notEmpty);
            }
        }
        for (Field field : c.getDeclaredFields()) {
            field.setAccessible(true);
            Object fieldval = null;
            try {
                fieldval = field.get(source);
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
            }
            if (fieldval != null && "serialVersionUID".equals(field.getName()) == false && "this$0".equals(field.getName()) == false) {
                String tmp = String.valueOf(fieldval);
                if (notEmpty == false || !StringUtils.notNullOrBlank(tmp)) {
                    if (field.getGenericType().equals(Date.class)) {
                        params.put(field.getName(), format.get().format((Date) fieldval));
                    } else {
                        params.put(field.getName(), fieldval);
                    }
                }
            }
        }
    }

    /**
     * 生成长度为length 的验证码
     *
     * @param length
     * @return
     */
    public static String getVerificationCode(int codeLen) {

        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < codeLen; i++) {

            sb.append(new Random().nextInt(10));
        }
        return sb.toString();
    }

    /**
     * 生成长度为length都为 0 的字符串
     *
     * @param length
     * @return
     */
    public static String getJointStringByZero(int len) {

        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < len; i++) {

            sb.append("0");
        }
        return sb.toString();
    }

    /**
     * 自增序列所需日期
     *
     * @return
     */
    public static Date getTodayEndTime() {
        Calendar todayEnd = Calendar.getInstance();
        todayEnd.set(Calendar.HOUR_OF_DAY, 23);
        todayEnd.set(Calendar.MINUTE, 59);
        todayEnd.set(Calendar.SECOND, 59);
        todayEnd.set(Calendar.MILLISECOND, 999);
        return todayEnd.getTime();
    }

    /**
     * 验证参数不可为 null
     *
     * @param objs
     */
    public static void validateNotNull(Object... objs) {
        if (objs != null && objs.length > 0) {
            for (int i = 0; i < objs.length; i++) {
                if (objs[i] == null) {
                    throw new IllegalArgumentException("objs[" + i + "] is null.");
                }
            }
        }
    }

    /**
     * 验证字符串不可为空
     *
     * @param strs
     */
    public static void validateNotEmpty(String... strs) {
        if (strs != null && strs.length > 0) {
            for (int i = 0; i < strs.length; i++) {
                if (StringUtils.trimToNull(strs[i]) == null) {
                    throw new IllegalArgumentException("strs[" + i + "] is null or empty.");
                }
            }
        }
    }

    /**
     * 去掉前后空格
     *
     * @param string
     * @return
     */
    public static String trimToNull(String str) {
        final String ts = trim(str);
        return isEmpty(ts) ? null : ts;
    }


    /**
     * 去掉字符串最后一位
     *
     * @param string
     * @return
     */
    public static String removeLastChar(String str) {
        if (StringUtils.isEmpty(str)) {
            return "";
        }
        return str.substring(0, str.length() - 1);
    }

    /**
     * 验证数字是否大于0
     *
     * @param ds
     */
    public static void validateGreaterThanZero(Number... ds) {
        if (ds != null && ds.length > 0) {
            for (int i = 0; i < ds.length; i++) {
                if (ds[i] == null || ds[i].doubleValue() <= 0) {
                    throw new IllegalArgumentException("ds[" + i + "] is null or less then 0.");
                }
            }
        }
    }

    public static boolean isNoneBlank(String str) {
        if (isEmpty(str)) {
            return false;
        }
        return true;
    }

    public static boolean isBlank(String str) {
        return isEmpty(str);
    }

    /**
     * 手机号中间四位脱敏
     *
     * @param str
     * @return
     */
    public static String simConceal(String str) {
        return str.substring(0, str.length() - (str.substring(3)).length()) + "****" + str.substring(7);
    }

    /**
     * 数组转换字符串
     */
    public static String arrayToString(String[] arr) {
        if (arr == null || arr.length == 0) {
            return "";
        }
        StringBuffer st = new StringBuffer();
        for (String s : arr) {
            st.append(s).append(Constants.Point.COMMA_SEPARATOR);
        }
        return removeLastChar(st.toString());
    }

    /**
     * Double 转string 去除科学记数法显示
     *
     * @param d
     * @return
     */
    public static String double2Str(Double d) {
        if (d == null) {
            return "";
        }
        NumberFormat nf = NumberFormat.getInstance();
        nf.setGroupingUsed(false);
        return (nf.format(d));
    }

    /**
	 * 2018年10月24日更新
	 * String转map
	 * @param str
	 * @return
	 */
	public static Map<String,String> getStringToMap(String str){
		//感谢bojueyou指出的问题
		//判断str是否有值
		if(null == str || "".equals(str)){
			return null;
		}
		//根据&截取
		String[] strings = str.split("&");
		//设置HashMap长度
		int mapLength = strings.length;
		//判断hashMap的长度是否是2的幂。
		if((strings.length % 2) != 0){
			mapLength = mapLength+1;
		}

		Map<String,String> map = new HashMap<>(mapLength);
		//循环加入map集合
		for (int i = 0; i < strings.length; i++) {
			//截取一组字符串
			String[] strArray = strings[i].split("=");
			//strArray[0]为KEY  strArray[1]为值
			map.put(strArray[0],strArray[1]);
		}
		return map;
	}
	
	/**
	 *
	 * map转str
	 * @param map
	 * @return
	 */
	public static String getMapToString(Map<String,String> map){
		Set<String> keySet = map.keySet();
		//将set集合转换为数组
		String[] keyArray = keySet.toArray(new String[keySet.size()]);
		//给数组排序(升序)
		Arrays.sort(keyArray);
		//因为String拼接效率会很低的，所以转用StringBuilder。博主会在这篇博文发后不久，会更新一篇String与StringBuilder开发时的抉择的博文。
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < keyArray.length; i++) {
			// 参数值为空，则不参与签名 这个方法trim()是去空格
			if (map.get(keyArray[i]).trim().length() > 0) {
				sb.append(keyArray[i]).append("=").append(map.get(keyArray[i]).trim());
			}
			if(i != keyArray.length-1){
				sb.append("&");
			}
		}
		return sb.toString();
	}
	
	/**
     * 获取指定长度纯字母随机码
     * @param len  字符长度
     * @return String
     */
    public static String getRandomCode(int len) {
        String code=RandomStringUtils.random(len,CODE_STR);
        return code;
    }
    
    /***
     * 獲取Ip地址信息
     * @return
     * @throws SocketException
     */
    public static String getRealIp() throws SocketException {
		String localip = null;// 本地IP，如果没有配置外网IP则返回它
		String netip = null;// 外网IP
		Enumeration<NetworkInterface> netInterfaces =
		NetworkInterface.getNetworkInterfaces();
		InetAddress ip = null;
		boolean finded = false;// 是否找到外网IP
		while (netInterfaces.hasMoreElements() && !finded) {
			NetworkInterface ni = netInterfaces.nextElement();
			Enumeration<InetAddress> address = ni.getInetAddresses();
			while (address.hasMoreElements()) {
				ip = address.nextElement();
				if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 外网IP
					netip = ip.getHostAddress();
					finded = true;
					break;
				} else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 内网IP
					localip = ip.getHostAddress();
				}
			}
		}

		if (netip != null && !"".equals(netip)) {
			return netip;
		} else {
			return localip;
		}
	}
    
    /**
	 * 生成随机字符串
	 * 
	 * @param length 长度
	 * @param isOnlyNum 是否仅使用数字
	 * @return
	 */
	public static String randomString(int length, boolean isOnlyNum) {
		int size = isOnlyNum ? 10 : 62;
		StringBuffer hash = new StringBuffer(length);
		for (int i = 0; i < length; i++) {
			hash.append(__randChars.charAt(__random.nextInt(size)));
		}
		return hash.toString();
	}
	
	
	/**
	 * 将中文转换成unicode.
	 * @param str
	 * @return 转换后的unicode字符串
	 */
	public static String getUnicode(String str){
		String result = "";
		char[] c = str.toCharArray();
		for(char tmp:c){	
			if(tmp > 255){  
				result += "\\"+"u" + Integer.toHexString(tmp);  
		          
		    }else  
				result += tmp;
		}
		return result;
	}
	
	/***
	 * sp20021010121212INPFOO
	 * @param prefix
	 * @return
	 */
	public static String getBusinessCode(String prefix) {
		return prefix + DateUtil.getDateFormateDate() + getRandomCode(6);
	}
	
	public static String stringSort(String str) {
		if(StringUtils.isBlank(str)) {
			return "";
		}
		if(str.indexOf(",") < 0) {
			return str;
		}
		String[] arr = str.split(",");
		Arrays.sort(arr);
		String smp = "";
		for(String s : arr) {
			smp = smp + s + ",";
		}
		return removeLastChar(smp);
	}
	
	
	
	public static String sortArray(String str) {
		if(str.indexOf(",") < 0) {
			return str;
		}
	    StringBuffer letterBuffer = new StringBuffer();
	    StringBuffer numberBuffer = new StringBuffer();
	    String[] arr = str.split(",");
	    for(String s : arr) {
	    	char m = s.charAt(0);
	        if(m >= '0' && m <= '9')
	            numberBuffer.append(s).append(",");
	        else
	            letterBuffer.append(s).append(",");
	    }
	    String mpStr = stringSort(removeLastChar(numberBuffer.toString()) + "," +  stringSort(removeLastChar(letterBuffer.toString())) );
	    if(mpStr.indexOf(",") == 0) {
	    	mpStr = mpStr.substring(1);
	    }
	    if(mpStr.indexOf(",") == mpStr.length()) {
	    	mpStr = mpStr.substring(0, mpStr.length() - 1);
	    }
	    return mpStr;
	}


	
	/**
	 * @return 返回采用JDK自身UUID生成器生成主键并替换 '-' 字符
	 */
	public final static String uuid() {
		return UUID.randomUUID().toString().replace("-", "");
	}
	
	
	public static String getMD5(String str) {
		String md5 = DigestUtils.md5DigestAsHex(str.getBytes());
		return md5;
	}
	
	
	public static Map<String, String> xmlToMap(String xml) {
        try {
            Map<String, String> data = new HashMap<>();
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            InputStream stream = new ByteArrayInputStream(xml.getBytes("UTF-8"));
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            stream.close();
            return data;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
	
	
	/**
     * 根据经纬度获取地址
     * @param lon
     * @param lat
     * @return
     */
    public static Map<String, String> getAddr(String lon, String lat) {
        String url = "http://restapi.amap.com/v3/geocode/regeo?key=2f548ae3a0af6c30012547b7cfc7e4cb&location=" + lon + "," + lat;
        String res = null;
        try {
        	res = HttpClientUtils.doGet(url);
        } catch (Exception e) {
            return null;
        }
        String temp = "{" +res.substring(res.indexOf("\"city\""), res.indexOf(",\"towncode\""))+"}";
        JSONObject json = JSONObject.parseObject(temp);
        Map<String, String> map = new HashMap<String, String>();
        map.put("province", json.getString("province"));
        map.put("city", "[]".equals(json.getString("city")) ? json.getString("province") : json.getString("city"));
        map.put("district", json.getString("district"));
        System.out.println(map);
        return map;
    }
    
    /**
     * 年  （一年中的第几天（从 0 到 365）*24+当前小时数） 后随机10个数
     */
    public static String getReminderSn() {
    	Calendar ca = Calendar.getInstance();//创建一个日期实例
    	ca.setTime(new Date());//实例化一个日期
    	System.out.println(ca.get(Calendar.HOUR_OF_DAY));
    	return ca.get(Calendar.DAY_OF_YEAR)*24 +"" + ca.get(Calendar.HOUR_OF_DAY) + "" + RandomStringUtils.random(10,CODE_DIGT);
    }

    /**
     * @return : String
     * @Description : 去除末字符串
     * @Creation Date : 2016年5月21日 下午10:29:16
     * @Author : chichangchao
     */
    public static String removeEndStr(final String str, final String remove) {
        if (!hasText(str) || !hasText(remove)) {
            return "";
        }
        if (str.endsWith(remove)) {
            return str.substring(0, str.length() - remove.length());
        }
        return str;
    }
}
